home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / Apple Location Manager / Sources / Utilities.c < prev    next >
Encoding:
Text File  |  1998-01-09  |  26.7 KB  |  1,003 lines  |  [TEXT/CWIE]

  1. /*
  2.      File:        Utilities.c
  3.  
  4.      Contains:    Location Manager SDK Sample Module handy routines
  5.  
  6.      Version:    ALM SDK 2.0
  7.                  Package:    Location Manager SDK 2.0
  8.  
  9.      Copyright:    © 1996-1997 by Apple Computer, Inc.
  10.                  All rights reserved.
  11.  
  12.      Bugs?:        Please include the the file and version information (from above) with
  13.                  the problem description.  Developers belonging to one of the Apple
  14.                  developer programs can submit bug reports to:
  15.  
  16.                      devsupport@apple.com
  17.  
  18. */
  19.  
  20. // ------------------------------------------------------------------------------------------------- 
  21.  
  22. // Module Include...
  23.  
  24. #include    "Utilities.h"
  25.  
  26. // Project Includes...
  27.  
  28. #include    "Sample.h"
  29.  
  30. // MacOS Includes...
  31.  
  32. #include    <FSM.h>
  33. #include    <Folders.h>
  34. #include    <Gestalt.h>
  35. #include    <LowMem.h>
  36. #include    <PLStringFuncs.h>
  37. #include    <Resources.h>
  38. #include    <Script.h>
  39.  
  40. // ANSI Includes...
  41.  
  42. #include    <string.h>
  43.  
  44. // ------------------------------------------------------------------------------------------------- 
  45.  
  46. // Readability Constants...
  47.  
  48. #define        kInvalidRefNum                        (-1)
  49. #define        kUseSetting                            false
  50. #define        kReadSetting                        true
  51. #define        kNoIdleProc                            NULL
  52. #define        kNoFilterProc                        NULL
  53. #define        kTimeToQuit                            (10*60)        // 10 seconds to quit...    
  54. #define        kDontUseIndex                        0
  55. #define        kNoFileName                            "\p"
  56. #define        kUseVRefNumOnly                        NULL
  57. #define        kExtractFileFlagsFromFinder            0
  58. #define        kGetMostRecentlyCreatedMatch        0
  59.  
  60. // Expressive Macros...
  61.  
  62. #define        ShareTime()                { EventRecord e; WaitNextEvent (0, &e, 1, NULL); }
  63. #define        EmptyAEDesc(desc)        { desc.descriptorType = typeNull; \
  64.                                             desc.dataHandle = NULL; }
  65. #define     SetFirstProcess(psn)    { psn.highLongOfPSN = 0; \
  66.                                             psn.lowLongOfPSN = kNoProcess; }
  67.  
  68. // ------------------------------------------------------------------------------------------------- 
  69.  
  70. // Local prototypes...
  71.  
  72. static OSErr
  73. QuitApplications (Boolean readOnly);
  74.     // Quit applications if appropriate...
  75.     
  76. static OSErr
  77. SendQuitApplication (Boolean* wasOpen, OSType creator);
  78.     // Send a "quit" AppleEvent to the application whose creator is given...
  79.  
  80. static OSErr
  81. SendLaunchApplication (OSType creator, LaunchFlags theFlags);
  82.     // Find the first application that matches the specified creator, and launch it...
  83.  
  84. static OSErr
  85. LaunchIt (ConstFSSpecPtr theApplication, LaunchFlags theFlags);
  86.     // Launch the specified application with the specified flags...
  87.  
  88. static Boolean
  89. FindProcessByCreator (ProcessSerialNumber* psn, OSType creator);
  90.     // Given a creator code, return the process serial number of the first matching process...
  91.     
  92. static Boolean
  93. ProcessManagerAvailable (void);
  94.     // Good way to tell if it's INIT time...
  95.     
  96. static Boolean
  97. ProcessBecameInvalid (ProcessSerialNumber* psn, UInt32 timeoutInTicks);
  98.     // Little routine to wait for a process to quit (since we can't wait for a reply
  99.     // event)...
  100.     
  101. static OSErr
  102. MakeAnFSSpec (SInt16 idx, SInt16 vRefNum, SInt32 parID, FSSpec* theSpec);
  103.     // Given a (1-based) index, a volume, and a parent directory ID, go out the
  104.     // resource fork, get the corresponding name, and make an FSSpec for it; do
  105.     // not return fnfErr for non-existant files...
  106.     
  107. static OSErr
  108. FSpSwapFile (FSSpecPtr theFile, UInt32 fileIdx, SettingPtr theSetting, 
  109.         ALMRebootFlags* flags);
  110.     // Retrieve the file specified by fileIdx (0-based) from theSetting, and, using the
  111.     // FSSpec, adjust the file...
  112.     
  113. static OSErr
  114. FSpAddFile (FSSpecPtr theFile, UInt32 fileIdx, SettingHandle setting, 
  115.         UInt32* nextByteToUse);
  116.     // Add the forks of the file specified by fileIndex (0-based) to the setting, starting at
  117.     // offset *nextByteToUse, and adjusting *nextByteToUse to the end of the file; also
  118.     // adjust the corresponding info record...
  119.     
  120. static OSErr
  121. FSpGetFileDates (FSSpecPtr theFile, UInt32* createDate, UInt32* modDate);
  122.     // Given a file, return its creation date and modification date...
  123.     
  124. static OSErr
  125. FSpSetFileDates (FSSpecPtr theFile, UInt32 createDate, UInt32 modDate);
  126.     // Set the creation and modification dates on the specified file...
  127.     
  128. static OSErr
  129. NewTempFile (FSSpec* theFile);
  130.     // Create a temporary file, returning its spec...
  131.  
  132. static OSErr
  133. FSpDTGetAPPL (SInt16 vRefNum, OSType creator, FSSpec* launchApplication);
  134.     // For the given volume, look up the application with the stipulated creator, and return
  135.     // a file spec for it...
  136.  
  137. // ------------------------------------------------------------------------------------------------- 
  138.  
  139. extern OSErr
  140. UseSetting (GlobalsHandle globals, SettingHandle setting, ALMRebootFlags* flags) {
  141.  
  142.     OSErr        err        = ConfirmFSSpecs (globals);
  143.     SInt8        svState    = HGetState ((Handle) globals);
  144.  
  145.     HLock ((Handle) globals);
  146.  
  147.     if (err == noErr) {
  148.         err = QuitApplications (kUseSetting);
  149.     } // if
  150.  
  151.     if (err == noErr) {
  152.  
  153.         GlobalsPtr    theGlobals    = *globals;
  154.         UInt32        fileCount     = theGlobals->fileCount;
  155.         UInt32        fileIdx;
  156.         SInt8        setState    = HGetState ((Handle) setting);
  157.  
  158.         // At this point, you need to decide whether you're going to convert old settings that
  159.         // the user might have created, or whether you're going to support them directly, or
  160.         // whatever.  In the case of the sample module, we didn't actually change the format of
  161.         // our settings from 1.0 SDK, but we did up the version number to see if you were
  162.         // paying attention; obviously, the new settings will generate an error if used with the
  163.         // old module, but, for purposes of this demonstration, we'll just pretend that they're
  164.         // the same here (because they are).  This just goes to point out how important it is
  165.         // to leave yourself a little "room for growth" in designing your settings format.  The
  166.         // alternative it to return an error to the user, which you can then DescribeError as
  167.         // "setting too old; please use the Location Manager control panel to update"...
  168.         
  169.         if ((**setting).version == kOldSettingVersion) {
  170.             (**setting).version = kSettingVersion;    // This doesn't mean they'll get written out!
  171.         } // if
  172.  
  173.         // Go through and swap each file's data...
  174.         
  175.         if ((**setting).version == kSettingVersion) {
  176.             HLock ((Handle) setting);
  177.             for (fileIdx = 0; fileIdx < fileCount; fileIdx += 1) {
  178.                 err = FSpSwapFile (&theGlobals->theFiles[fileIdx], fileIdx, *setting, flags);
  179.                 if (err != noErr) {
  180.                     break;
  181.                 } // if
  182.             } // for
  183.         } else {
  184.             err = paramErr;
  185.         } // if
  186.         
  187.         HSetState ((Handle) setting, setState);
  188.  
  189.     } // if
  190.  
  191.     HSetState ((Handle) globals, svState);
  192.  
  193.     return err;
  194.  
  195. } // UseSetting
  196.  
  197. // ------------------------------------------------------------------------------------------------- 
  198.  
  199. extern OSErr
  200. ReadSetting (GlobalsHandle globals, SettingHandle setting) {
  201.  
  202.     OSErr        err        = ConfirmFSSpecs (globals);
  203.     SInt8        svState    = HGetState ((Handle) globals);
  204.  
  205.     HLock ((Handle) globals);
  206.  
  207.     if (err == noErr) {
  208.         err = QuitApplications (kReadSetting);
  209.     } // if
  210.  
  211.     if (err == noErr) {
  212.         
  213.         GlobalsPtr    theGlobals    = *globals;
  214.         UInt32        fileCount     = theGlobals->fileCount;
  215.         UInt32        fileIdx;
  216.         UInt32        freeDataOffset;
  217.         
  218.         // First make room for the fixed-size records; we'll add space for each
  219.         // file's data later...
  220.         
  221.         if (fileCount > 0) {
  222.         
  223.             freeDataOffset = sizeof (SettingRec) + 
  224.                                 sizeof (FileInfoRec) * (fileCount - kVariableLengthArray);
  225.             SetHandleSize ((Handle) setting, freeDataOffset);
  226.             err = MemError ();
  227.             
  228.             // Go through and add each file's data...
  229.             
  230.             if (err == noErr) {
  231.                 (**setting).fileCount = 0;
  232.                 (**setting).version = kSettingVersion;
  233.                 for (fileIdx = 0; fileIdx < fileCount; fileIdx += 1) {
  234.                     err = FSpAddFile (&theGlobals->theFiles[fileIdx], fileIdx, setting, &freeDataOffset);
  235.                     if (err != noErr) {
  236.                         break;
  237.                     } // if
  238.                     (**setting).fileCount = fileIdx + 1;
  239.                 } // for
  240.             } // if
  241.  
  242.         } // if
  243.         
  244.     } // if
  245.  
  246.     HSetState ((Handle) globals, svState);
  247.  
  248.     return err;
  249.  
  250. } // ReadSetting
  251.  
  252. // ------------------------------------------------------------------------------------------------- 
  253.  
  254. extern OSErr
  255. ConfirmFSSpecs (GlobalsHandle globals) {
  256.  
  257.     OSErr        err        = noErr;
  258.     SInt8        svState    = HGetState ((Handle) globals);
  259.     
  260.     // Our assumption is that if the fileCount is 0, we need to go out and
  261.     // create FSSpecs for the files...
  262.     
  263.     if ((**globals).fileCount == 0) {
  264.     
  265.         SInt16        fileCount;
  266.         
  267.         HUnlock ((Handle) globals);    // May need to resize...
  268.  
  269.         // Each file occupies two resources; one is a string, and the other is
  270.         // a bunch of flags (it's done this way to avoid some messy variable-size
  271.         // data), but we only need the string at this point...
  272.  
  273.         fileCount = Count1Resources (kFilesRsrcType);
  274.  
  275.         if (fileCount > 0) {
  276.         
  277.             SInt16        vRefNum;
  278.             SInt32        parID;
  279.             GlobalsPtr    theGlobals;
  280.         
  281.             // Prepare the globals to receive our data, and look up the preferences
  282.             // folder just this once...
  283.         
  284.             SetHandleSize ((Handle) globals, 
  285.                     sizeof (Globals) + sizeof (FSSpec) * (fileCount - kVariableLengthArray));
  286.             err = MemError ();
  287.             if (err == noErr) {
  288.                 (**globals).fileCount = fileCount;
  289.                 err = FindFolder (kOnSystemDisk, kPreferencesFolderType, 
  290.                             kDontCreateFolder, &vRefNum, &parID);
  291.             } // if
  292.  
  293.             // With all that, we can lock down the globals, and stuff FSSpecs into
  294.             // the array one at a time...
  295.  
  296.             if (err == noErr) {
  297.             
  298.                 SInt16        curFileIdx;
  299.             
  300.                 HLock ((Handle) globals);
  301.                 
  302.                 theGlobals = *globals;
  303.  
  304.                 for (curFileIdx = 0; curFileIdx < fileCount; curFileIdx += 1) {
  305.                 
  306.                     err = MakeAnFSSpec (curFileIdx + 1, vRefNum, parID, 
  307.                             &theGlobals->theFiles[curFileIdx]);
  308.                     if (err != noErr) {
  309.                         break;
  310.                     } // if
  311.                 
  312.                 } // for
  313.             
  314.             } // if
  315.  
  316.         } // if
  317.     
  318.     } // if
  319.     
  320.     HSetState ((Handle) globals, svState);
  321.  
  322.     return err;
  323.  
  324. } // ConfirmFSSpecs
  325.  
  326. // ------------------------------------------------------------------------------------------------- 
  327.  
  328. extern void
  329. InsParamStr (StringPtr matchThis, StringPtr replaceWithThis, StringPtr replaceInThis) {
  330.  
  331.     UInt8        matchLen        = StrLength (matchThis);
  332.     UInt8        replaceLen        = StrLength (replaceWithThis);
  333.     UInt8        replaceInLen    = StrLength (replaceInThis);
  334.     Ptr            matchPtr;
  335.     Str255        tempStr;
  336.  
  337.     matchPtr = PLstrstr (replaceInThis, matchThis);
  338.     PLstrcpy (tempStr, replaceInThis);
  339.  
  340.     if (matchPtr != NULL) {
  341.     
  342.         UInt8        matchPos    = (UInt32) matchPtr - (UInt32) replaceInThis;
  343.         UInt8        contPos        = matchPos + matchLen;
  344.         UInt8        frontLen    = matchPos - 1;
  345.         UInt8        backLen        = replaceInLen - frontLen - matchLen;
  346.         
  347.         BlockMoveData (&replaceWithThis[1], &replaceInThis[matchPos], replaceLen);
  348.         BlockMoveData (&tempStr[contPos], &replaceInThis[frontLen + replaceLen + 1], backLen);
  349.         replaceInThis[0] = ((UInt32) replaceInLen - (UInt32) matchLen + (UInt32) replaceLen);
  350.         
  351.     } // if
  352.  
  353. } // InsParamStr
  354.  
  355. // ------------------------------------------------------------------------------------------------- 
  356.  
  357. extern OSErr
  358. LaunchApplications (LaunchFlags theFlags) {
  359.  
  360.     OSErr                        err        = noErr;
  361.  
  362.     ApplicationListHandle        appsHandle;
  363.  
  364.     appsHandle = (ApplicationListHandle) Get1Resource (kAppsRsrcType, kAppsEditRsrcID);
  365.  
  366.     if (appsHandle != NULL) {
  367.         
  368.         UInt32                    curApp;
  369.         ApplicationListPtr        apps;
  370.         UInt8                    flags;
  371.     
  372.         HLock ((Handle) appsHandle);
  373.         apps = *appsHandle;
  374.         
  375.         for (curApp = 0; curApp < apps->applicationCount; curApp += 1) {
  376.             flags = apps->applications[curApp].flags;
  377.             if (flags == kAppListLaunchFromEdit) {
  378.                 err = SendLaunchApplication (apps->applications[curApp].applicationCode, theFlags);
  379.                 if (err != noErr) {
  380.                     break;
  381.                 } // if
  382.             } // if
  383.         } // for
  384.     
  385.         HUnlock ((Handle) appsHandle);
  386.         ReleaseResource ((Handle) appsHandle);
  387.         
  388.     } else {
  389.     
  390.         err = resNotFound;
  391.     
  392.     } // if
  393.     return err;
  394.  
  395. } // LaunchApplications
  396.  
  397. // ------------------------------------------------------------------------------------------------- 
  398.  
  399. static OSErr
  400. QuitApplications (Boolean readOnly) {
  401.  
  402.     OSErr                        err        = noErr;
  403.     ApplicationListHandle        appsHandle;
  404.  
  405.     appsHandle = (ApplicationListHandle) Get1Resource (kAppsRsrcType, kAppsQuitRsrcID);
  406.  
  407.     if (appsHandle != NULL) {
  408.         
  409.         UInt32                    curApp;
  410.         ApplicationListPtr        apps;
  411.         UInt8                    flags;
  412.         Boolean                    wasOpen;
  413.     
  414.         HLock ((Handle) appsHandle);
  415.         apps = *appsHandle;
  416.         
  417.         for (curApp = 0; curApp < apps->applicationCount; curApp += 1) {
  418.             flags = apps->applications[curApp].flags;
  419.             if ((flags == kAppListQuitOnGetOrSet) || 
  420.                     (readOnly && (flags == kAppListQuitOnGet)) || 
  421.                         (!readOnly && (flags == kAppListQuitOnSet))) {
  422.                 err = SendQuitApplication (&wasOpen, apps->applications[curApp].applicationCode);
  423.                 if (err != noErr) {
  424.                     break;
  425.                 } // if
  426.             } // if
  427.         } // for
  428.     
  429.         HUnlock ((Handle) appsHandle);
  430.         ReleaseResource ((Handle) appsHandle);
  431.         
  432.     } else {
  433.     
  434.         err = resNotFound;
  435.     
  436.     } // if
  437.  
  438.     return err;
  439.  
  440. } // QuitApplications
  441.  
  442. // ------------------------------------------------------------------------------------------------- 
  443.  
  444. static OSErr
  445. SendQuitApplication (Boolean* wasOpen, OSType creator) {
  446.  
  447.     OSErr                    err                    = noErr;
  448.     ProcessSerialNumber        applicationPSN;
  449.     AEAddressDesc            applicationAddr;
  450.     AppleEvent                quitEvent;
  451.     AppleEvent                theReply;
  452.     
  453.     EmptyAEDesc (applicationAddr);
  454.     EmptyAEDesc (quitEvent);
  455.     EmptyAEDesc (theReply);
  456.  
  457.     // Find a process matching the creator, if any; if it is found, send it an
  458.     // AppleEvent to quit (it does support the core suite, right?)...
  459.     
  460.     *wasOpen = FindProcessByCreator (&applicationPSN, creator);
  461.     
  462.     if (*wasOpen) {
  463.         if (err == noErr) {
  464.             err = AECreateDesc (typeProcessSerialNumber, &applicationPSN, 
  465.                         sizeof (applicationPSN), &applicationAddr);
  466.         } // if
  467.         if (err == noErr) {
  468.             err = AECreateAppleEvent (kCoreEventClass, kAEQuitApplication,
  469.                         &applicationAddr, kAutoGenerateReturnID, kAnyTransactionID, 
  470.                         &quitEvent); 
  471.         } // if
  472.         if (err == noErr) {
  473.             err = AESend (&quitEvent, &theReply, kAENoReply | kAENeverInteract,
  474.                         kAEHighPriority, kAEDefaultTimeout, kNoIdleProc,
  475.                         kNoFilterProc);
  476.         } // if
  477.         if (err == noErr) {
  478.             if (!ProcessBecameInvalid (&applicationPSN, kTimeToQuit)) {
  479.                 err = kSampleCouldNotQuitIdx;    // We'll tell the user we tried...
  480.             } // if
  481.         } // if
  482.     } // if
  483.  
  484.     (void) AEDisposeDesc (&applicationAddr);
  485.     (void) AEDisposeDesc (&quitEvent);
  486.  
  487.     return err;
  488.  
  489. } // SendQuitApplication
  490.  
  491. // ------------------------------------------------------------------------------------------------- 
  492.  
  493. static OSErr
  494. SendLaunchApplication (OSType creator, LaunchFlags theFlags) {
  495.  
  496.     OSErr                    err                 = noErr;
  497.     VCBPtr                    volumesLeft            = NULL;
  498.     QHdrPtr                    volumeList;
  499.  
  500.     // Walk through the volume control block list...
  501.     
  502.     volumeList = GetVCBQHdr ();
  503.     if (volumeList != NULL) {
  504.         volumesLeft = (VCBPtr) volumeList->qHead;
  505.     } // if
  506.     
  507.     while (volumesLeft != NULL) {
  508.     
  509.         FSSpec        launchApplication;
  510.     
  511.         // Grab the vRefNum; use it too look up the creator in the desktop database on this disk...
  512.         
  513.         err = FSpDTGetAPPL (volumesLeft->vcbVRefNum, creator, &launchApplication);
  514.         if (err == noErr) {
  515.             LaunchIt (&launchApplication, theFlags);
  516.         } // if
  517.     
  518.         // Advance to the next one; if we got to the end of the list, then it's hopeless, so
  519.         // return an error...
  520.         
  521.         volumesLeft = (VCBPtr) volumesLeft->qLink;
  522.         if (volumesLeft == NULL) {
  523.             err = fnfErr;
  524.         } // if
  525.     
  526.     } // if
  527.  
  528.     return err;
  529.  
  530. } // SendLaunchApplication
  531.  
  532. // ------------------------------------------------------------------------------------------------- 
  533.  
  534. static OSErr
  535. LaunchIt (ConstFSSpecPtr theApplication, LaunchFlags theFlags) {
  536.  
  537.     OSErr                    err                    = noErr;
  538.     LaunchParamBlockRec        lpb;
  539.  
  540.     lpb.launchBlockID         = extendedBlock;
  541.     lpb.launchEPBLength     = extendedBlockLen;
  542.     lpb.launchFileFlags     = kExtractFileFlagsFromFinder;
  543.     lpb.launchControlFlags     = theFlags;
  544.     lpb.launchAppSpec         = (FSSpecPtr) theApplication;
  545.     
  546.     err = LaunchApplication (&lpb);
  547.  
  548. BAIL:    
  549.     return err;
  550.  
  551. } // LaunchIt
  552.  
  553. // ------------------------------------------------------------------------------------------------- 
  554.  
  555. static Boolean
  556. FindProcessByCreator (ProcessSerialNumber* psn, OSType creator) {
  557.  
  558.     OSErr                    err                 = noErr;
  559.     Boolean                    found                = false;
  560.     ProcessInfoRec            curProcessInfo;
  561.     ProcessSerialNumber        curPSN; 
  562.     
  563.     SetFirstProcess (curPSN);
  564.     
  565.     // If we're running at INIT time, none of this will work (and we don't need to
  566.     // do it anyway!), so 
  567.     
  568.     if (ProcessManagerAvailable ()) {
  569.  
  570.         do {
  571.             curProcessInfo.processInfoLength     = sizeof (curProcessInfo);
  572.             curProcessInfo.processName            = NULL;
  573.             curProcessInfo.processAppSpec        = NULL;
  574.             if (err == noErr) {
  575.                 err = GetNextProcess (&curPSN);
  576.             } // if
  577.             if (err == noErr) {
  578.                 err = GetProcessInformation (&curPSN, &curProcessInfo);
  579.             } // if
  580.             if (err == noErr) {
  581.                 if (curProcessInfo.processSignature == creator) {
  582.                     *psn = curPSN;
  583.                     found = true;
  584.                     break;
  585.                 } // if
  586.             } // if
  587.         } while (err == noErr);
  588.     
  589.     } // if
  590.  
  591.     return found;
  592.  
  593. } // FindProcessByCreator
  594.  
  595. // ------------------------------------------------------------------------------------------------- 
  596.  
  597. static Boolean
  598. ProcessManagerAvailable (void) {
  599.  
  600.     OSErr        err;
  601.     SInt32        response;
  602.     Boolean        reply;
  603.     
  604.     err = Gestalt (gestaltOSAttr, &response);
  605.     
  606.     reply = (err == noErr) && (response & (1 << gestaltLaunchControl));
  607.     
  608.     return reply;
  609.  
  610. } // ProcessManagerAvailable
  611.  
  612. // ------------------------------------------------------------------------------------------------- 
  613.  
  614. static Boolean
  615. ProcessBecameInvalid (ProcessSerialNumber* psn, UInt32 timeoutInTicks) {
  616.  
  617.     OSErr            err                 = noErr;
  618.     Boolean            stillAround         = true;
  619.     UInt32            startTime             = LMGetTicks ();
  620.     UInt32            curTime                = startTime;
  621.     UInt32            endTime                = startTime + timeoutInTicks;
  622.     ProcessInfoRec    processInfo;
  623.     
  624.     // Wait around, being background friendly, for the specified process to 
  625.     // terminate...
  626.  
  627.     do {
  628.         ShareTime ();
  629.         if (err == noErr) {
  630.             processInfo.processInfoLength     = sizeof (processInfo);
  631.             processInfo.processName            = NULL;
  632.             processInfo.processAppSpec        = NULL;
  633.             err = GetProcessInformation (psn, &processInfo);
  634.             if ((err == paramErr) || (err == procNotFound)) {
  635.                 stillAround = false;
  636.                 break;
  637.             } // if
  638.         } // if
  639.         curTime = LMGetTicks ();
  640.     } while (curTime < endTime);
  641.     
  642.     return !stillAround;
  643.  
  644. } // ProcessBecameInvalid
  645.  
  646. // ------------------------------------------------------------------------------------------------- 
  647.  
  648. static OSErr
  649. MakeAnFSSpec (SInt16 idx, SInt16 vRefNum, SInt32 parID, FSSpec* theSpec) {
  650.  
  651.     OSErr                    err                    = noErr;
  652.     FileEntryHandle            fileName;
  653.  
  654.     fileName = (FileEntryHandle) Get1IndResource (kFilesRsrcType, idx);
  655.     
  656.     if (fileName != NULL) {
  657.         HLock ((Handle) fileName);
  658.         err = FSMakeFSSpec (vRefNum, parID, (StringPtr) *fileName, theSpec);
  659.         if (err == fnfErr) {
  660.             err = noErr;
  661.         } // if
  662.         HUnlock ((Handle) fileName);
  663.         ReleaseResource ((Handle) fileName);
  664.     } else {
  665.         err = resNotFound;
  666.     } // if
  667.  
  668.     return err;
  669.  
  670. } // MakeAnFSSpec
  671.  
  672. // ------------------------------------------------------------------------------------------------- 
  673.  
  674. static OSErr
  675. FSpSwapFile (FSSpecPtr theFile, UInt32 fileIdx, SettingPtr theSetting, 
  676.         ALMRebootFlags* flags) {
  677.  
  678.     OSErr                    err                    = noErr;
  679.     FSSpec                    tempFile;
  680.     SInt16                    dataForkRef            = kInvalidRefNum;
  681.     SInt16                    resForkRef            = kInvalidRefNum;
  682.     Ptr                        dataForkStart;
  683.     Ptr                        resForkStart;
  684.     SInt32                    dataForkLen;
  685.     SInt32                    resForkLen;
  686.     FSSpec                    destSpec;
  687.  
  688.     // Our strategy here is to create a temp file, put our data in it, close the file,
  689.     // swap it with the real one (if the real one exists), then reset the creation and
  690.     // modification dates....
  691.     
  692.     // Create a temp file and open its forks...
  693.     
  694.     if (err == noErr) {
  695.         err = NewTempFile (&tempFile);
  696.     } // if
  697.     if (err == noErr) {
  698.         err = FSpOpenDF (&tempFile, fsRdWrPerm, &dataForkRef);
  699.     } // if
  700.     if (err == noErr) {
  701.         err = FSpOpenRF (&tempFile, fsRdWrPerm, &resForkRef);
  702.     } // if
  703.  
  704.     // Write the data out of the setting...
  705.     
  706.     dataForkStart    = ((Ptr) theSetting) + theSetting->fileInfo[fileIdx].dataForkOffset;
  707.     resForkStart    = ((Ptr) theSetting) + theSetting->fileInfo[fileIdx].resForkOffset;
  708.     dataForkLen        = theSetting->fileInfo[fileIdx].dataForkLen;
  709.     resForkLen        = theSetting->fileInfo[fileIdx].resForkLen;
  710.     
  711.     if (err == noErr) {
  712.         err = FSWrite (dataForkRef, &dataForkLen, dataForkStart);
  713.     } // if
  714.     if (err == noErr) {
  715.         err = FSWrite (resForkRef, &resForkLen, resForkStart);
  716.     } // if
  717.  
  718.     // Swap the files (or move the one, if the other does not exist)...
  719.         
  720.     if (err == noErr) {
  721.         err = FSpExchangeFiles (theFile, &tempFile);
  722.         if (err == noErr) {
  723.             err = FSpDelete (&tempFile);
  724.         } else if (err == fnfErr) {
  725.             err = FSMakeFSSpec (theFile->vRefNum, theFile->parID, kNoFileName, &destSpec);
  726.             if (err == noErr) {
  727.                 err = FSpCatMove (&tempFile, &destSpec);
  728.             } // if
  729.         } // if
  730.     } // if
  731.  
  732.     // Restore the file's dates...
  733.     
  734.     if (err == noErr) {
  735.         err = FSpSetFileDates (theFile, theSetting->fileInfo[fileIdx].dateCreated,
  736.                      theSetting->fileInfo[fileIdx].dateModified);
  737.     } // if
  738.     
  739.     // Now, the fiddly part--using the index, get the reboot flags for this file...
  740.     
  741.     if (err == noErr) {
  742.     
  743.         // We'll do it this "roundabout" way so that we know we're correctly matching
  744.         // resource ids...
  745.  
  746.         FileEntryHandle        fileName     = (FileEntryHandle) Get1IndResource (kFilesRsrcType, fileIdx + 1);
  747.         SInt16                rsrcID;
  748.         ResType                rsrcType;
  749.         Str255                rsrcName;
  750.         FileFlagsHandle        theFlags;
  751.         
  752.         if (fileName != NULL) {
  753.  
  754.             GetResInfo ((Handle) fileName, &rsrcID, &rsrcType, rsrcName);
  755.             err = ResError ();
  756.             if (err == noErr) {
  757.                 theFlags = (FileFlagsHandle) Get1Resource (kRestartRsrcType, rsrcID);
  758.                 if ((**theFlags).flags & kRestartIfChanged != 0) {
  759.                     *flags = kALMExtensions;
  760.                 } // if
  761.                 ReleaseResource ((Handle) theFlags);
  762.             } // if
  763.             ReleaseResource ((Handle) fileName);
  764.  
  765.         } else {
  766.             err = resNotFound;
  767.         } // if
  768.     
  769.     } // if
  770.  
  771.     // Cleanup...
  772.  
  773.     if (dataForkRef != kInvalidRefNum) {
  774.         (void) FSClose (dataForkRef);
  775.     } // if
  776.     if (resForkRef != kInvalidRefNum) {
  777.         (void) FSClose (resForkRef);
  778.     } // if
  779.  
  780.     return err;
  781.  
  782. } // FSpSwapFile
  783.  
  784. // ------------------------------------------------------------------------------------------------- 
  785.  
  786. static OSErr
  787. FSpAddFile (FSSpecPtr theFile, UInt32 fileIdx, SettingHandle setting, 
  788.         UInt32* nextByteToUse) {
  789.  
  790.     OSErr                    err                    = noErr;
  791.     SInt16                    dataForkRef            = kInvalidRefNum;
  792.     SInt16                    resForkRef            = kInvalidRefNum;
  793.     SInt32                    dataForkLen;
  794.     SInt32                    resForkLen;
  795.     SInt8                    svState                = HGetState ((Handle) setting);
  796.     SInt32                    newHandleSize;
  797.     UInt32                    freeDataOffset        = *nextByteToUse;
  798.     UInt32                    createDate;
  799.     UInt32                    modDate;
  800.     
  801.     // Open both forks (no dining philosophers, please), and get the Dates...
  802.     
  803.     if (err == noErr) {
  804.         err = FSpGetFileDates (theFile, &createDate, &modDate);
  805.     } // if
  806.     if (err == noErr) {
  807.         err = FSpOpenDF (theFile, fsRdPerm, &dataForkRef);
  808.     } // if
  809.     if (err == noErr) {
  810.         err = FSpOpenRF (theFile, fsRdPerm, &resForkRef);
  811.     } // if
  812.  
  813.     // Determine how long the forks are...
  814.     
  815.     if (err == noErr) {
  816.         err = GetEOF (dataForkRef, &dataForkLen);
  817.     } // if
  818.     if (err == noErr) {
  819.         err = GetEOF (resForkRef, &resForkLen);
  820.     } // if
  821.  
  822.     // Resize the handle so we can store the data in it, then lock it down for reading...
  823.     
  824.     if (err == noErr) {
  825.         newHandleSize = freeDataOffset + dataForkLen + resForkLen;
  826.         SetHandleSize ((Handle) setting, newHandleSize);
  827.         err = MemError ();
  828.     } // if
  829.     if (err == noErr) {
  830.     
  831.         SettingPtr        theSetting;
  832.         FileInfoPtr        theFileInfo;
  833.         Ptr                startAddr;
  834.     
  835.         HLock ((Handle) setting);
  836.         
  837.         theSetting = *setting;
  838.         theFileInfo = &theSetting->fileInfo[fileIdx];
  839.         startAddr = ((Ptr) theSetting) + freeDataOffset;
  840.         
  841.         // Record information about the file 
  842.         
  843.         theFileInfo->dateCreated        = createDate;
  844.         theFileInfo->dateModified        = modDate;
  845.         theFileInfo->dataForkOffset        = freeDataOffset;
  846.         theFileInfo->dataForkLen        = dataForkLen;
  847.         theFileInfo->resForkOffset        = freeDataOffset + dataForkLen;
  848.         theFileInfo->resForkLen            = resForkLen;
  849.         
  850.         // Finally, read in the forks at their alloted locations...
  851.         
  852.         if ((err == noErr) && (dataForkLen > 0)) {
  853.             err = FSRead (dataForkRef, &dataForkLen, startAddr);
  854.         } // if
  855.         if ((err == noErr) && (resForkLen > 0)) {
  856.             err = FSRead (resForkRef, &resForkLen, startAddr + dataForkLen);
  857.         } // if
  858.         
  859.     } // if
  860.  
  861.     // Cleanup...
  862.  
  863.     if (dataForkRef != kInvalidRefNum) {
  864.         (void) FSClose (dataForkRef);
  865.     } // if
  866.     if (resForkRef != kInvalidRefNum) {
  867.         (void) FSClose (resForkRef);
  868.     } // if
  869.  
  870.     *nextByteToUse = newHandleSize;
  871.  
  872.     HSetState ((Handle) setting, svState);
  873.  
  874.     return err;
  875.  
  876. } // FSpAddFile
  877.  
  878. // ------------------------------------------------------------------------------------------------- 
  879.  
  880. static OSErr
  881. FSpGetFileDates (FSSpecPtr theFile, UInt32* createDate, UInt32* modDate) {
  882.  
  883.     OSErr            err        = noErr;
  884.  
  885.     if (err == noErr) {
  886.     
  887.         HParamBlockRec        paramBlock;
  888.         HFileParam*            fileParam = ¶mBlock.fileParam;
  889.         
  890.         fileParam->ioCompletion        = NULL;
  891.         fileParam->ioNamePtr        = (StringPtr) theFile->name;
  892.         fileParam->ioVRefNum        = theFile->vRefNum;
  893.         fileParam->ioFDirIndex        = kDontUseIndex;
  894.         fileParam->ioDirID            = theFile->parID;
  895.         
  896.         err = PBHGetFInfoSync (¶mBlock);
  897.         
  898.         if (err == fnfErr) {
  899.             *createDate        = 0;
  900.             *modDate        = 0;
  901.             err = noErr;
  902.         } else {
  903.             *createDate        = fileParam->ioFlCrDat;
  904.             *modDate        = fileParam->ioFlMdDat;
  905.         } // if
  906.         
  907.     } // if
  908.  
  909.     return err;
  910.  
  911. } // FSpGetFileDates
  912.  
  913. // ------------------------------------------------------------------------------------------------- 
  914.  
  915. static OSErr
  916. FSpSetFileDates (FSSpecPtr theFile, UInt32 createDate, UInt32 modDate) {
  917.  
  918.     OSErr            err        = noErr;
  919.  
  920.     if (err == noErr) {
  921.     
  922.         HParamBlockRec        paramBlock;
  923.         HFileParam*            fileParam = ¶mBlock.fileParam;
  924.         
  925.         fileParam->ioCompletion        = NULL;
  926.         fileParam->ioNamePtr        = (StringPtr) theFile->name;
  927.         fileParam->ioVRefNum        = theFile->vRefNum;
  928.         fileParam->ioFDirIndex        = kDontUseIndex;
  929.         fileParam->ioDirID            = theFile->parID;
  930.         
  931.         err = PBHGetFInfoSync (¶mBlock);
  932.         
  933.         if (err == noErr) {
  934.             // Need to restore PBHGetFInfoSync because it changes ioDirID to a fileID
  935.             // but we want the dirID for the PBHSetFInfoSync call to work!
  936.             fileParam->ioDirID            = theFile->parID;
  937.             fileParam->ioFlCrDat        = createDate;
  938.             fileParam->ioFlMdDat        = modDate;
  939.             err = PBHSetFInfoSync (¶mBlock);
  940.         } // if
  941.         
  942.     } // if
  943.  
  944.     return err;
  945.  
  946. } // FSpSetFileDates
  947.  
  948. // ------------------------------------------------------------------------------------------------- 
  949.  
  950. static OSErr
  951. NewTempFile (FSSpec* theFile) {
  952.  
  953.     OSErr            err        = noErr;
  954.     SInt16            vRefNum;
  955.     SInt32            parID;
  956.  
  957.     if (err == noErr) {
  958.     
  959.         err = FindFolder (kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
  960.                 &vRefNum, &parID);
  961.         if (err == noErr) {
  962.             err = FSMakeFSSpec (vRefNum, parID, "\pModule Temp", theFile);
  963.             if (err == noErr) {
  964.                 err = dupFNErr;
  965.             } else if (err == fnfErr) {
  966.                 err = FSpCreate (theFile, '\?\?\?\?', '\?\?\?\?', smSystemScript);
  967.             } // if
  968.         } // if
  969.         
  970.     } // if
  971.  
  972.     return err;
  973.  
  974. } // NewTempFile
  975.  
  976. // ------------------------------------------------------------------------------------------------- 
  977.  
  978. static OSErr
  979. FSpDTGetAPPL (SInt16 vRefNum, OSType creator, FSSpec* launchApplication) {
  980.  
  981.     OSErr            err        = noErr;
  982.     DTPBRec            desktopPB;
  983.  
  984.     if (err == noErr) {
  985.         desktopPB.ioNamePtr            = kUseVRefNumOnly;
  986.         desktopPB.ioVRefNum            = vRefNum;
  987.         err = PBDTOpenInform (&desktopPB);
  988.     } // if
  989.     if (err == noErr) {
  990.         desktopPB.ioNamePtr            = launchApplication->name;
  991.         desktopPB.ioIndex             = kGetMostRecentlyCreatedMatch;
  992.         desktopPB.ioFileCreator        = creator;
  993.         err = PBDTGetAPPLSync (&desktopPB);
  994.     } // if
  995.     if (err == noErr) {
  996.         launchApplication->vRefNum    = desktopPB.ioVRefNum;
  997.         launchApplication->parID    = desktopPB.ioAPPLParID;
  998.     } // if
  999.  
  1000.     return err;
  1001.  
  1002. } // FSpDTGetAPPL
  1003.